package thinkingInJava.concurrency;
//: concurrency/E25_Restaurant.java
/********************** Exercise 25 ***********************
 * In the Chef3 class in RestaurantT2.java, return from run()
 * after calling shutdownNow() and observe the difference
 * in behavior.
 *********************************************************/
import java.util.concurrent.*;
import static thinkingInJava.YTool.YPrint.*;
class Meal2 {
	private final int orderNum;
	public Meal2(int orderNum) { this.orderNum = orderNum; }
	public String toString() { return "Meal2 " + orderNum; }
}
class WaitPerson2 implements Runnable {
	private RestaurantT2 restaurant;
	public WaitPerson2(RestaurantT2 r) { restaurant = r; }
	public void run() {
		try {
			while(!Thread.interrupted()) {
				synchronized(this) {
					while(restaurant.meal == null)
						wait(); // ... for the chef to produce a meal
				}
				print("Waitperson got " + restaurant.meal);
				synchronized(restaurant.chef) {
					restaurant.meal = null;
					restaurant.chef.notifyAll(); // Ready for another
				}
			}
		} catch(InterruptedException e) {
			print("WaitPerson2 interrupted");
		}
	}
}
class Chef3 implements Runnable {
	private RestaurantT2 restaurant;
	private int count = 0;
	public Chef3(RestaurantT2 r) { restaurant = r; }
	public void run() {
		try {
			while(!Thread.interrupted()) {
				synchronized(this) {
					while(restaurant.meal != null)
						wait(); // ... for the meal to be taken
				}
				if(++count == 10) {
					print("Out of food, closing");
					restaurant.exec.shutdownNow();
					return;
				}
				printnb("Order up! ");
				synchronized(restaurant.waitPerson) {
					restaurant.meal = new Meal2(count);
					restaurant.waitPerson.notifyAll();
				}
				TimeUnit.MILLISECONDS.sleep(100);
			}
		} catch(InterruptedException e) {
			print("Chef3 interrupted");
		}
	}
}
class RestaurantT2 {
	Meal2 meal;
	ExecutorService exec = Executors.newCachedThreadPool();
	WaitPerson2 waitPerson = new WaitPerson2(this);
	Chef3 chef = new Chef3(this);
	public RestaurantT2() {
		exec.execute(chef);
		exec.execute(waitPerson);
	}
	public static void main(String[] args) {
		new RestaurantT2();
	}
}
public class Restaurant2 {
	public static void main(String[] args) {
		new RestaurantT2();
	}
} /* Output: (Sample)
Order up! Waitperson got Meal2 1
Order up! Waitperson got Meal2 2
Order up! Waitperson got Meal2 3
Order up! Waitperson got Meal2 4
Order up! Waitperson got Meal2 5
Order up! Waitperson got Meal2 6
Order up! Waitperson got Meal2 7
Order up! Waitperson got Meal2 8
Order up! Waitperson got Meal2 9
Out of food, closing
WaitPerson2 interrupted
 *///:~
//The “Order up!” and “Chef3 interrupted” messages no longer appear, since the
//Chef3 task exits immediately.
